class Graphe {
  constructor(container, option) {
    this.canvasConfig = {
      offset: {
        x: 0,
        y: 0,
      }, //缩放偏移
      scale: 1, //缩放比例
      scaleStep: 0.1, //每次缩放产生的变化量
      maxScale: 2, //最大缩放倍数
      minScale: 0.6, //最小缩放倍数
    };
    this.clickTooltipInfor = {
      //点击的tooltip信息
      from: "",
      to: "",
    };
    this.nodes = []; //节点信息
    this.container = container; //容器
    this.ArrowTextRects = []; //连线中间的矩形文本区域 在方法addArrow中增加
    this.connections = []; //连线信息
    let originoption = {
      r: 18,
      circleColor: "#47d9a1",
    };
    this.option = Object.assign(originoption, option); //合并配置项
    this.init();
  }
  init() {
    var canvas = document.createElement("canvas"); //创建canvas元素
    this.container.appendChild(canvas); //添加到页面上
    var ctx = canvas.getContext("2d");
    this.ctx = ctx;
    this.canvas = canvas;
    var that = this;
    canvas.onmousedown = function (evt1) {
      var { canvasConfig, nodes, ctx, connections } = that;
      let dragStartPixel = {
        x: 0,
        y: 0,
      };
      const canvasPosition = that.getMousePosition(evt1);
      const p1 = {
        x: canvasPosition.x,
        y: canvasPosition.y,
      };
      let cirle = that.getClickCircle(p1, nodes);
      if (cirle) {
        dragStartPixel.x = evt1.offsetX;
        dragStartPixel.y = evt1.offsetY;
        canvas.onmousemove = function (evt) {
          console.log();
          let tooltip = document.getElementsByClassName("my-tooltip")[0];
          if (tooltip) {
            tooltip.parentNode.removeChild(tooltip);
          }
          cirle.x += (evt.offsetX - dragStartPixel.x) / canvasConfig.scale; //更新圆的位置信息
          cirle.y += (evt.offsetY - dragStartPixel.y) / canvasConfig.scale; //更新圆的位置信息
          dragStartPixel.x = evt.offsetX;
          dragStartPixel.y = evt.offsetY;
          that.clear();
          ctx.setTransform(
            //设置放缩 平移
            canvasConfig.scale,
            0,
            0,
            canvasConfig.scale,
            canvasConfig.offset.x,
            canvasConfig.offset.y
          );
          //根据圆圈信息画圈
          nodes.forEach((item, index) => {
            if (item.status != -1) {
              that.addCircle(item);
              that.addCanvasText(item, that.swValue);
            }
          });
          //画线 包括线上的db
          connections.forEach((element) => {
            that.addArrow(element, that.getDoubelArrows(connections));
          });
        };
        //鼠标松开
        document.addEventListener("mouseup", (e) => {
          canvas.onmousemove = null;
        });
      } else {
        dragStartPixel.x = evt1.offsetX;
        dragStartPixel.y = evt1.offsetY;
        canvas.onmousemove = function (evt) {
          let tooltip = document.getElementsByClassName("my-tooltip")[0];
          if (tooltip) {
            tooltip.parentNode.removeChild(tooltip);
          }
          canvasConfig.offset.x +=
            (evt.offsetX - dragStartPixel.x) / canvasConfig.scale;
          canvasConfig.offset.y +=
            (evt.offsetY - dragStartPixel.y) / canvasConfig.scale;
          /* 更新鼠标位置 */
          dragStartPixel.x = evt.offsetX;
          dragStartPixel.y = evt.offsetY;
          /* 清空画布 */
          that.clear();
          //设置放缩 平移
          ctx.setTransform(
            canvasConfig.scale,
            0,
            0,
            canvasConfig.scale,
            canvasConfig.offset.x,
            canvasConfig.offset.y
          );
          //根据圆圈信息画圈
          nodes.forEach((item, index) => {
            if (item.status != -1) {
              that.addCircle(item);
              that.addCanvasText(item, that.swValue);
            }
          });
          //画线 包括线上的db
          connections.forEach((element) => {
            that.addArrow(element, that.getDoubelArrows(connections));
          });
        };
        //鼠标松开
        document.addEventListener("mouseup", (e) => {
          canvas.onmousemove = null;
        });
      }
    };
    canvas.addEventListener("wheel", (e) => {
      let { canvasConfig, nodes, connections, ctx } = this;
      let tooltip = document.getElementsByClassName("my-tooltip")[0];
      if (tooltip) {
        tooltip.parentNode.removeChild(tooltip);
      }
      //阻止默认行为
      e.preventDefault();
      //以鼠标为中心缩放
      const canvasPosition = this.getMousePosition(e);
      //以屏幕中心为中心缩放
      // const canvasPosition = {x:width/2,y:height/2};
      //获取的坐标为相对左上角的坐标,需要转换为真实坐标 整个坐标变化过程是以真实坐标来进行运算的
      const realCanvasPosition = {
        x: canvasPosition.x - canvasConfig.offset.x,
        y: canvasPosition.y - canvasConfig.offset.y,
      };
      const { scaleStep } = canvasConfig;
      //变化偏移量维度转换 例如我们以(100,100)这个维度进行缩放,每次变化10,10这个变化量在0.9倍率下看起来是奇怪的需要进行维度转换,同98行
      const deltaX = (realCanvasPosition.x * scaleStep) / canvasConfig.scale;
      const deltaY = (realCanvasPosition.y * scaleStep) / canvasConfig.scale;
      //上下滚轮分别赋值
      if (e.wheelDelta > 0) {
        //放大
        if (canvasConfig.scale >= canvasConfig.maxScale) {
          return;
        }
        canvasConfig.scale += scaleStep;
        //偏移值做叠加
        canvasConfig.offset.x -= deltaX;
        canvasConfig.offset.y -= deltaY;
      } else {
        //缩小
        if (canvasConfig.scale <= canvasConfig.minScale) {
          return;
        }
        canvasConfig.scale -= scaleStep;
        canvasConfig.offset.x += deltaX;
        canvasConfig.offset.y += deltaY;
      }
      //伸缩平移
      this.clear();
      //缩放是针对原始画布来实现的
      ctx.setTransform(
        canvasConfig.scale,
        0,
        0,
        canvasConfig.scale,
        canvasConfig.offset.x,
        canvasConfig.offset.y
      );
      nodes.forEach((item) => {
        if (item.status != -1) {
          this.addCircle(item);
          this.addCanvasText(item, this.swValue);
        }
      });
      connections.forEach((element) => {
        this.addArrow(element, this.getDoubelArrows(connections));
      });
    });
    canvas.addEventListener("click", function (e) {
      let { ArrowTextRects } = that;
      let position = {};
      position.x = e.offsetX;
      position.y = e.offsetY;
      let show = that.getClickRectangle(position, ArrowTextRects);
      //点击到db值
      if (show) {
        that.addTooltip(show.position);
      } else {
        //点击到空白地方
        let tooltip = document.getElementsByClassName("my-tooltip")[0];
        if (tooltip) {
          tooltip.parentNode.removeChild(tooltip);
        }
      }
    });
    // canvas.addEventListener("resize", () => {});
  }
  update(newNodes, links) {
    this.clear();
    let { canvasConfig, nodes, ctx } = this;
    nodes = this.nodes;
    let { width, height } = this.getContainerSize();
    ctx.setTransform(
      canvasConfig.scale,
      0,
      0,
      canvasConfig.scale,
      canvasConfig.offset.x,
      canvasConfig.offset.y
    );
    if (newNodes.length) {
      //是否为[]
      let increasedNodes = []; //新增节点
      let decreaseNodes = []; //减少节点
      if (nodes.length) {
        //判断nodes是不是为空
        nodes.forEach((item) => {
          //当前设备在新的里面找不到 设备丢失将设备状态置为-1
          decreaseNodes = newNodes.filter((ele) => {
            return item.id == ele.id;
          });
          if (!decreaseNodes.length) {
            //设备减少
            item.status = -1;
          }
          newNodes.forEach((key) => {
            if (key.meshIp == item.meshIp) {
              for (let entry in key) {
                //修改属性值
                if (entry == 'noise'  || entry == "name ") {
                  item[entry] = key[entry];
                }
              }
            }
          });
        });
        //判断是不是设备增加
        newNodes.forEach((item) => {
          let add = [];
          add = nodes.filter((ele) => {
            //新设备在原来设备中找不到，则为新增
            if (item.id == ele.id) {
              ele.status = 1; //设备增加
            }
            return item.id == ele.id;
          });
          //不能找到
          if (!add.length) {
            increasedNodes.push(item);
          }
        });

        if (increasedNodes) {
          //新增设备重新计算坐标
          let count = nodes.length + increasedNodes.length;
          let n = nodes.length;
          for (n; n < count; n = n * 2) {}
          let radians = (Math.PI / 180) * Math.round(360 / n);
          let r = Math.min(height, width) * 0.35;
          increasedNodes.forEach((item, index) => {
            item.x = width / 2 + r * Math.sin(radians * (2 * index + 1));
            item.y = height / 2 + r * Math.cos(radians * (2 * index + 1));
          });
          nodes = nodes.concat(increasedNodes);

          this.nodes = nodes; //修改节点信息
          nodes.forEach((item) => {
            if (item.status != -1) {
              /* 绘制未曾消失的圈 */
              this.addCircle(item);
              this.addCanvasText(item, this.swValue);
            }
          });
        }
      } else {
        let r = Math.min(height, width) * 0.35;
        let computerPoints = this.ComputerPixels(
          r,
          width / 2,
          height / 2,
          newNodes.length
        );
        newNodes.forEach((item, index) => {
          item.x = computerPoints[index].x;
          item.y = computerPoints[index].y;
        });
        newNodes.forEach((item) => {
          if (item.status != -1) {
            this.addCircle(item);
            this.addCanvasText(item, this.swValue);
          }
        });
        this.nodes = newNodes;
      }
      //画线画db值
      this.connections = links;
      links.forEach((element) => {
        this.addArrow(element, this.getDoubelArrows(this.connections));
      });
      let tooltip = document.getElementsByClassName("my-tooltip")[0];
      if (tooltip) {
        console.log(this.clickTooltipInfor, 329);
        let clickTooltipInfor = this.clickTooltipInfor;
        let index = links.findIndex((it) => {
          return (
            (clickTooltipInfor.from == it.from &&
              clickTooltipInfor.to == it.to) ||
            (clickTooltipInfor.from == it.to && clickTooltipInfor.to == it.from)
          );
        });
        if (index > -1) {
          this.addTooltip(this.clickTooltipInfor);
        } else {
          tooltip.parentNode.removeChild(tooltip);
        }
      }
    }
  }
  clear() {
    let { width, height } = this.getContainerSize();
    this.canvas.width = width * 0;
    this.canvas.height = height * 0;
    this.canvas.width = width * 1;
    this.canvas.height = height * 1;
  }
  getItemById(id, items) {
    let filterItems = [];
    filterItems = items.filter((it) => {
      return it.id == id;
    });
    return filterItems[0];
  }
  getLineColor(value) {
    let lineColor = "";
    switch (true) {
      case value >= 150:
        return (lineColor = "black");
        break;
      case 15 <= value && value < 25:
        lineColor = "#EBB056"; //黄色
        break;
      case value < 15:
        lineColor = "#FF5555"; //红色
        break;
      default:
        lineColor = "green"; //绿色
    }
    return lineColor;
  }
  addCircle(option) {
    let ctx = this.ctx;
    let { x, y } = option; //绘制圆
    let r = this.option.r;
    ctx.beginPath();
    ctx.arc(x, y, r, 0, 2 * Math.PI);
    // ctx.stroke();  //圆填充后无需绘线
    ctx.fillStyle = this.option.circleColor;
    ctx.fill();
    ctx.closePath();
  }
  addCanvasText(option, swValue) {
    let ctx = this.ctx;
    let { x, y, name } = option;
    ctx.font = "14px sans-serif";
    let subName = name || option.defaultName || option.meshIp;
    if (swValue) {
      subName += " " + "底噪:" + "-" + option.noise + "dBm";
    }
    ctx.fillText(subName, x - 14, y + 36);
    ctx.fill();
    ctx.closePath();
  }
  getDistance(p1, p2) {
    return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
  }
  getClickCircle(p1, circles) {
    let { scale, offset } = this.canvasConfig;
    let circle = null;
    let r = this.option.r;
    for (let i = 0; i < circles.length; i++) {
      let distance = this.getDistance(p1, {
        x: circles[i].x * scale + offset.x,
        y: circles[i].y * scale + offset.y,
      });
      if (distance <= 2 * r * scale) {
        circle = circles[i];
      }
    }
    return circle;
  }
  ComputerPixels(r, sx, sy, count) {
    //根据获取坐标位置
    let pixels = [];
    let radians = (Math.PI / 180) * Math.round(360 / count);
    for (let i = 0; i < count; i++) {
      let x = sx + r * Math.sin(radians * i);
      let y = sy + r * Math.cos(radians * i);
      // y = y * 0.1
      y = (y * 1).toFixed(2) * 1;
      pixels.push({ x, y });
    }
    return pixels;
  }
  getClickRectangle(position, rectangles) {
    let { scale, offset } = this.canvasConfig;
    let rectangle = null;
    if (rectangles.length > 0) {
      rectangles.forEach((item, index) => {
        let { x, x1, y, y1 } = item.position;
        x = x * scale + offset.x;
        x1 = x1 * scale + offset.x;
        y = y * scale + offset.y;
        y1 = y1 * scale + offset.y;
        if (
          x <= position.x &&
          position.x <= x1 &&
          y1 <= position.y &&
          position.y <= y
        ) {
          rectangle = rectangles[index];
          return;
        }
      });
    }
    return rectangle;
  }
  addArrow(arrow, doubelArrows) {
    let ctx = this.ctx;
    let option = {};
    let ArrowTextRects = this.ArrowTextRects;
    var r = this.option.r;
    {
      let from = this.getItemById(arrow.from, this.nodes);
      let to = this.getItemById(arrow.to, this.nodes);
      let filterArrows = [];
      filterArrows = doubelArrows.filter((item) => {
        return item.from == arrow.from && item.to === arrow.to;
      });
      option = Object.assign({}, arrow);
      // console.log(from,arrow);
      option.xA = from.x;
      option.yA = from.y;
      option.xB = to.x;
      option.yB = to.y;
      if (filterArrows.length) {
        option.strokeStyle = this.getLineColor(filterArrows[0].signal);
        option.signal = filterArrows[0].subSignal;
      } else {
        option.strokeStyle = this.getLineColor(arrow.signal);
      }
    }
    let { xA, yA, xB, yB, θ = 15, strokeStyle, from, to, signal } = option;
    var lineWidth = option.needBold ? 5 : 2;
    let L = 10;
    //计算与x轴的偏移角 坐标原点为左上点,无需分类
    let a = Math.atan2(yB - yA, xB - xA);
    //文本样式
    ctx.font = "14px sans-serif";
    let x = (xA + xB) / 2;
    let y = (yA + yB) / 2;
    //文字位置计算
    ctx.fillStyle = "black";
    ctx.textBaseline = "bottom";
    if (signal) {
      signal = signal + "dB";
      ctx.fillText(signal, (xA + xB) / 2, (yA + yB) / 2);
    } else {
    }
    let rectangle = {};
    rectangle.position = {
      x,
      y,
      x1: x + signal.length * 14,
      y1: y - 14,
      from,
      to,
    };
    if (ArrowTextRects.length > 0) {
      //未收集直接存入数据
      let index = this.ArrowTextRects.findIndex((it) => {
        return it.position.from == option.from && it.position.to == option.to;
      });
      if (index < 0) {
        ArrowTextRects.push(rectangle);
      } else {
        ArrowTextRects[index].position = rectangle.position; //rectangle为当当前坐标信息 修改已有坐标信息
      }
    } else {
      //未收集
      ArrowTextRects.push(rectangle);
    }
    //圈圆心减去rcosa和rsina得出两圆心连线与圆的交点坐标值
    xA += r * Math.cos(a);
    yA += r * Math.sin(a);
    xB -= r * Math.cos(a);
    yB -= r * Math.sin(a);
    let xC = xB - L * Math.cos(a + (θ * Math.PI) / 180); // θ=30
    let yC = yB - L * Math.sin(a + (θ * Math.PI) / 180);
    let xD = xB - L * Math.cos(a - (θ * Math.PI) / 180);
    let yD = yB - L * Math.sin(a - (θ * Math.PI) / 180);
    ctx.beginPath();
    ctx.moveTo(xA, yA); //起点
    ctx.lineTo(xB, yB); //终点
    ctx.moveTo(xC, yC); //起点
    ctx.lineTo(xB, yB); //终点
    ctx.lineTo(xD, yD); //终点
    ctx.lineWidth = lineWidth; //箭头的粗细，可以根据需要自己选择
    ctx.strokeStyle = strokeStyle;
    ctx.stroke(); //绘线
  }
  getMousePosition(e) {
    return {
      x: e.offsetX,
      y: e.offsetY,
    };
  }
  getContainerSize() {
    let height = this.container.offsetHeight;
    let width = this.container.offsetWidth;
    return { height, width };
  }
  getDoubelArrows(arrows) {
    let doubelArrows = [];
    for (let i = 0; i < arrows.length; i++) {
      for (let j = i + 1; j < arrows.length; j++) {
        if (arrows[i].from == arrows[j].to && arrows[i].to == arrows[j].from) {
          let signal = Math.min(arrows[i].signal, arrows[j].signal);
          doubelArrows.push(
            {
              from: arrows[i].from,
              to: arrows[i].to,
              signal,
              subSignal: signal,
            },
            {
              from: arrows[i].to,
              signal,
              to: arrows[i].from,
              subSignal: "",
            }
          );
        }
      }
    }

    return doubelArrows;
  }
  addTooltip(tooltip) {
    let { scale, offset } = this.canvasConfig;
    this.clickTooltipInfor = tooltip;
    let tooltipDom = document.getElementsByClassName("my-tooltip")[0];
    let connections = this.connections.filter((it) => {
      return (
        (it.from == tooltip.from && it.to == tooltip.to) ||
        (it.to == tooltip.from && it.from == tooltip.to)
      );
    });
    let content = ""; //内容
    connections.forEach((it) => {
      let originIP = this.getItemById(it.from, this.nodes).meshIp;
      let desIP = this.getItemById(it.to, this.nodes).meshIp;
      let singnal = it.signal + "dB";
      content += `<div class='tooltip-item'>源IP：${originIP}</div><div class='tooltip-item'>目的IP：${desIP}</div><div class='tooltip-item'>信噪比：${singnal}</div>`;
    });
    let previous = this.container.parentNode.parentNode.previousElementSibling;
    
    
    if (!tooltipDom) {
      //没有tooltip的时候
      // getBoundingClientRect

      let pixel = { x: tooltip.x, y: tooltip.y }; //tootip位置信息
      let dom = document.createElement("div");
      dom.innerHTML = content;
      dom.className = "my-tooltip";
      dom.style.position = "absolute";
      dom.style.left = pixel.x * scale + offset.x + parseInt(previous.style.width) + "px";
      dom.style.top = pixel.y * scale + offset.y +parseInt(getComputedStyle(previous).padding)+2 + "px";
      let container = this.container.parentNode;
      container.appendChild(dom);
    } else {
      let pixelX = 0;
      let pixelY = 0;
      this.nodes.forEach((it) => {
        if (it.id == tooltip.from || it.id == tooltip.to) {
          pixelX += it.x / 2;
          pixelY += it.y / 2;
        }
      });
      tooltipDom.innerHTML = content;
      tooltipDom.style.position = "absolute";
      tooltipDom.style.left = pixelX * scale + offset.x +  parseInt(previous.style.width)+ "px";
      tooltipDom.style.top = pixelY * scale + offset.y +parseInt(getComputedStyle(previous).padding)+2+ "px";
    }
  }
}
// export default Graphe;
// let mock = {
//   points: [
//     {
//       id: "121",
//       name: "121号",
//       meshIp: "192.168.1.121",
//       noise: 91,
//       defaultName: "#121",
//     },
//     {
//       id: "138",
//       name: "138号",
//       meshIp: "192.168.1.138",
//       noise: 91,
//       defaultName: "#138",
//     },
//     {
//       id: "139",
//       name: "139号",
//       meshIp: "192.168.1.139",
//       noise: 91,
//       defaultName: "#139",
//     },
//     {
//       id: "140",
//       name: "140号",
//       meshIp: "192.168.1.140",
//       noise: 91,
//       defaultName: "#140",
//     },
//     {
//       id: "141",
//       name: "141号",
//       meshIp: "192.168.1.141",
//       noise: 91,
//       defaultName: "#141",
//     },
//     {
//       id: "142",
//       name: "142号",
//       meshIp: "192.168.1.142",
//       noise: 91,
//       defaultName: "#142",
//     },
//   ],
//   lines: [
//     { from: "121", to: "138", signal: 104, needBold: 0 },
//     { from: "138", to: "121", signal: 160, needBold: 0 },
//     { from: "138", to: "139", signal: 20, needBold: 0 },
//     { from: "139", to: "138", signal: 30, needBold: 0 },
//   ],
// };
